﻿using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Repository.DataBase;
using System.Text.RegularExpressions;
using Domain.Infrastructure;
using Microsoft.EntityFrameworkCore;

namespace System.Repository.Base
{
    /// <summary>
    /// 泛 数据仓库 泛型基本类 实现
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class RepositoryBase<T> : IRepositoryBase<T>
    where T : class, new()
    {
        /// <summary>
        /// ef 上下文选项
        /// </summary>
        public IDbContextConfig ContextConfig;
        /// <summary>
        /// 数据库上下文
        /// </summary>
        public readonly LiAnDbContext Dbcontext;
        protected RepositoryBase() : this(new DbContextConfig())
        {
        }
        protected RepositoryBase(IDbContextConfig config)
        {
            ContextConfig = config;
            Dbcontext = new LiAnDbContext(config.Create());
        }
        public DbTransaction DbTransaction { get; set; }
        //public IRepositoryBase<T> BeginTrans()
        //{


        //    DbConnection dbConnection = ((IObjectContextAdapter)Dbcontext).ObjectContext.Connection;
        //    if (dbConnection.State == ConnectionState.Closed)
        //    {
        //        dbConnection.Open();
        //    }
        //    DbTransaction = dbConnection.BeginTransaction();
        //    return this;
        //}

        /// <summary>
        /// 事务
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        public bool Transaction(Func<bool> func)
        {

            //using (var tran = Dbcontext.Database.BeginTransaction())
            //{
            //    try
            //    { 
            //        Dbcontext.Entry(model).State = EntityState.Added;
            //        Dbcontext.Entry(userLogOnEntity).State = EntityState.Added;

            //        //执行事务
            //        var result = Dbcontext.SaveChanges() > 0;
            //        if (result)
            //        {
            //            temp = true;
            //            tran.Commit();
            //        }
            //        else
            //        {
            //            tran.Rollback();
            //        } 
            //    }
            //    catch (Exception)
            //    {

            //        tran.Rollback();
            //    }
            //}

            // 事务例子
            bool temp = false;
            using (var tran = Dbcontext.Database.BeginTransaction())
            {
                try
                {
                    var result = func();//执行事务
                    if (result)
                    {
                        temp = true;
                        tran.Commit();
                    }
                    else
                    {
                        tran.Rollback();
                    }
                }
                catch (Exception)
                {
                    tran.Rollback();
                }
            }

            return temp;
        }
        public bool Update(T model)
        {
            var entry = Dbcontext.Entry<T>(model);
            Dbcontext.Set<T>().Attach(model);
            entry.State = EntityState.Modified;
            return Dbcontext.SaveChanges() > 0;
        }

        public virtual bool Delete(string key)
        {
            var entity = GetEntity(key);
            Dbcontext.Set<T>().Attach(entity);
            Dbcontext.Entry(entity).State = EntityState.Deleted;
            return Dbcontext.SaveChanges() > 0;
        }

        public T GetModel(object key)
        {

            // var list = Dbcontext.Set<T>().AsNoTracking().ToList();
            // return Dbcontext.Set<T>().Find(key);
            return Dbcontext.Set<T>().Find(key);
        }
        //public T FindEntity(Expression<Func<T, bool>> predicate)
        //{
        //    return Dbcontext.Set<T>().FirstOrDefault(predicate);
        //}
        public T GetEntity(string key)
        { 
            return GetModel(key);
        }

        public T GetModel(string key)
        {
           
            return GetModel((object)key);

        }
        public T GetModel(Expression<Func<T, bool>> predicate)
        {
            return Dbcontext.Set<T>().FirstOrDefault(predicate);
        }

        public List<T> GetList()
        {
            return Dbcontext.Set<T>().ToList();
        }

        public List<T> GetList(Expression<Func<T, bool>> predicate)
        {
            return Dbcontext.Set<T>().Where(predicate).ToList();
        }
        public List<T> IQueryable(Expression<Func<T, bool>> predicate)
        {
            return Dbcontext.Set<T>().Where(predicate).ToList();
        }


        public List<T> GetList(Pagination pagination)
        {
            bool isAsc = pagination.Sort.ToLower() == "asc";
            string[] order = pagination.Sort.Split(',');
            MethodCallExpression resultExp = null;
            var tempData = Dbcontext.Set<T>().AsQueryable();
            foreach (string item in order)
            {
                string orderPart = item;
                orderPart = Regex.Replace(orderPart, @"\s+", " ");
                string[] orderArry = orderPart.Split(' ');
                string orderField = orderArry[0];
                if (orderArry.Length == 2)
                {
                    isAsc = orderArry[1].ToUpper() == "ASC";
                }
                var parameter = Expression.Parameter(typeof(T), "t");
                var property = typeof(T).GetProperty(orderField);
                if (property != null)
                {
                    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
                    var orderByExp = Expression.Lambda(propertyAccess, parameter);
                    resultExp = Expression.Call(typeof(Queryable), isAsc ? "OrderBy" : "OrderByDescending", new[] { typeof(T), property.PropertyType }, tempData.Expression, Expression.Quote(orderByExp));
                }
            }
            if (resultExp != null) tempData = tempData.Provider.CreateQuery<T>(resultExp);
            pagination.Records = tempData.Count();
            tempData = tempData.Skip(pagination.Rows * pagination.Page).Take(pagination.Rows).AsQueryable();
            return tempData.ToList();
        }

        public List<T> GetList(Pagination pagination, Expression<Func<T, bool>> predicate)
        {
            bool isAsc = pagination.Sort.ToLower() == "asc";
            string[] order = pagination.Sort.Split(',');
            MethodCallExpression resultExp = null;
            var tempData = Dbcontext.Set<T>().Where(predicate);
            foreach (string item in order)
            {
                string orderPart = item;
                orderPart = Regex.Replace(orderPart, @"\s+", " ");
                string[] orderArry = orderPart.Split(' ');
                string orderField = orderArry[0];
                if (orderArry.Length == 2)
                {
                    isAsc = orderArry[1].ToUpper() == "ASC";
                }
                var parameter = Expression.Parameter(typeof(T), "t");
                var property = typeof(T).GetProperty(orderField);
                if (property != null)
                {
                    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
                    var orderByExp = Expression.Lambda(propertyAccess, parameter);
                    resultExp = Expression.Call(typeof(Queryable), isAsc ? "OrderBy" : "OrderByDescending", new[] { typeof(T), property.PropertyType }, tempData.Expression, Expression.Quote(orderByExp));
                }
            }
            if (resultExp != null)
            {
                tempData = tempData.Provider.CreateQuery<T>(resultExp);
                pagination.Records = tempData.Count();
                tempData = tempData.Skip(pagination.Rows * pagination.Page).Take(pagination.Rows).AsQueryable();
            }
            return tempData.ToList();
        }
        public bool Insert(T entity)
        {
            Dbcontext.Entry(entity).State = EntityState.Added;
            return Dbcontext.SaveChanges() > 0;
        }
        public bool Insert(List<T> entitys)
        {
            foreach (var entity in entitys)
            {
                Dbcontext.Entry(entity).State = EntityState.Added;
            }
            return Dbcontext.SaveChanges() > 0;
        }


        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        //public int Update(T entity)
        //{

        //    ////处理上下文中存在的 对象
        //    //Exists(entity);

        //    //Dbcontext.Set<T>().Attach(entity);
        //    //PropertyInfo[] props = entity.GetType().GetProperties();
        //    //foreach (PropertyInfo prop in props)
        //    //{
        //    //    if (prop.GetValue(entity, null) != null)
        //    //    {
        //    //        if (prop.GetValue(entity, null).ToString() == "&nbsp;")
        //    //            Dbcontext.Entry(entity).Property(prop.Name).CurrentValue = null;
        //    //        Dbcontext.Entry(entity).Property(prop.Name).IsModified = true;
        //    //    }
        //    //}
        //    //return Dbcontext.SaveChanges();


        //    Dbcontext.Entry(entity).State = EntityState.Unchanged;
        //    PropertyInfo[] props = entity.GetType().GetProperties();
        //    foreach (PropertyInfo prop in props)
        //    {
        //        if (prop.GetValue(entity, null) != null)
        //        {
        //            if (prop.GetValue(entity, null).ToString() == "&nbsp;")
        //                Dbcontext.Entry(entity).Property(prop.Name).CurrentValue = null;
        //            Dbcontext.Entry(entity).Property(prop.Name).IsModified = true;
        //        }
        //    }
        //    // Dbcontext.UpdateAsync()
        //    Dbcontext.Configuration.ValidateOnSaveEnabled = false;
        //    return Dbcontext.SaveChanges();


        //}
        public bool Delete(T entity)
        {
            Dbcontext.Set<T>().Attach(entity);
            Dbcontext.Entry(entity).State = EntityState.Deleted;
            return Dbcontext.SaveChanges() > 0;
        }
        public int Delete(Expression<Func<T, bool>> predicate)
        {
            var entitys = Dbcontext.Set<T>().Where(predicate).ToList();
            entitys.ForEach(m => Dbcontext.Entry(m).State = EntityState.Deleted);
            return Dbcontext.SaveChanges();
        }
      


        public List<T> FindList(Pagination pagination)
        {
            bool isAsc = pagination.Sort.ToLower() == "asc";
            string[] order = pagination.Sort.Split(',');
            MethodCallExpression resultExp = null;
            var tempData = Dbcontext.Set<T>().AsQueryable();
            foreach (string item in order)
            {
                string orderPart = item;
                orderPart = Regex.Replace(orderPart, @"\s+", " ");
                string[] orderArry = orderPart.Split(' ');
                string orderField = orderArry[0];
                if (orderArry.Length == 2)
                {
                    isAsc = orderArry[1].ToUpper() == "ASC";
                }
                var parameter = Expression.Parameter(typeof(T), "t");
                var property = typeof(T).GetProperty(orderField);
                if (property != null)
                {
                    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
                    var orderByExp = Expression.Lambda(propertyAccess, parameter);
                    resultExp = Expression.Call(typeof(Queryable), isAsc ? "OrderBy" : "OrderByDescending", new[] { typeof(T), property.PropertyType }, tempData.Expression, Expression.Quote(orderByExp));
                }
            }
            if (resultExp != null) tempData = tempData.Provider.CreateQuery<T>(resultExp);
            pagination.Records = tempData.Count();
            tempData = tempData.Skip(pagination.Rows * (pagination.Page)).Take(pagination.Rows).AsQueryable();
            return tempData.ToList();
        }
        public List<T> FindList(Expression<Func<T, bool>> predicate, Pagination pagination)
        {
            bool isAsc = pagination.Order.ToLower() == "asc";
            string[] order = pagination.Sort.Split(',');
            MethodCallExpression resultExp = null;
            var tempData = Dbcontext.Set<T>().Where(predicate);
            foreach (string item in order)
            {
                string orderPart = item;
                orderPart = Regex.Replace(orderPart, @"\s+", " ");
                string[] orderArry = orderPart.Split(' ');
                string orderField = orderArry[0];
                if (orderArry.Length == 2)
                {
                    isAsc = orderArry[1].ToUpper() == "ASC";
                }
                var parameter = Expression.Parameter(typeof(T), "t");
                var property = typeof(T).GetProperty(orderField);
                if (property != null)
                {
                    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
                    var orderByExp = Expression.Lambda(propertyAccess, parameter);
                    resultExp = Expression.Call(typeof(Queryable), isAsc ? "OrderBy" : "OrderByDescending", new[] { typeof(T), property.PropertyType }, tempData.Expression, Expression.Quote(orderByExp));
                }
            }
            if (resultExp != null)
            {
                tempData = tempData.Provider.CreateQuery<T>(resultExp);
                pagination.Records = tempData.Count();
                tempData = tempData.Skip(pagination.Rows * pagination.Page).Take(pagination.Rows).AsQueryable();
            }
            return tempData.ToList();
        }




    }
}
